from kivy.app import App

from dryfire.model.targetsModel import \
    PaperPlateDryFireTargetModel, BeerCanDryFireTargetModel, \
    HeadDryFireTargetModel, HipsAndHeadDryFireTargetModel, \
    TorsoDryFireTargetModel, ISPCMetricCZoneDryFireTargetModel, \
    ISPCClassicCZoneDryFireTargetModel
from dryfire.view.targetSlide import TargetSlide
from dryfire.model.persistentData import CalibrationsModel


class CalibrationsViewModel(object):
    """
    The view model for the InitialView class.
    """

    def __init__(self, view):
        self._view = view
        self._appdata = App.get_running_app().appdata
        self._record_ident = None
        self._record = {}

    # view methods

    def v_initialize_view(self):
        # initialize view with calibrations records
        calibrations = self._appdata['calibrations']
        idents = calibrations.data.keys()
        for i in idents:
            record = calibrations.get(i)
            self._view.vm_add_calibration(i, record['description']) 
        
    # step 1 : the user pressed the add a new record button
    
    def w_handle_create_button_on_press(self, instance):
        self._record_ident = None
        self._record = self._appdata['calibrations'].default_record
        self.w_calibrate()
        
    # other step 1 : the user selects a calibration record action
    #  to edit or delete
    
    def w_handle_calibrations_record(self, ident):
        # the user has selected a calibration record
        self._record_ident = ident
        self._record = self._appdata['calibrations'].get(ident)
        self.select_a_calibration_record_option()

    def select_a_calibration_record_option(self):
        from dryfire.view.calibrationsView import CalibrationsView
        # offer options for the record
        calibrations = self._appdata['calibrations']
        if calibrations.count == 1:
            self.w_calibrate()
        else:
            options = CalibrationsView.commands
            self._view.select_options('Options',
                                      options,
                                      options[0],
                                      self.w_handle_calibrations_record_command,
                                      help='What would you like to do with this record?')

    def w_handle_calibrations_record_command(self, command):
        from dryfire.view.calibrationsView import CalibrationsView
        if command == CalibrationsView.edit_command:
            self.w_calibrate()
        elif command == CalibrationsView.delete_command:
            ranges = self._appdata['ranges']
            if ranges.using_calibration(self._record_ident):
                question = "You are using this calibration with some of your"\
                " target setups. If you delete this calibration those target"\
                " setups will also be deleted.\n"
            else:
                question = "" 
            # let the user confirm deletion
            question += 'Are you sure that you want to '\
                       'delete the calibration record %s?' % (self._record['description'])
            self._view.question_yes_no('Delete a Calibration Record.',
                                       question,
                                       self.delete_a_calibration,
                                       back_handler=self.select_a_calibration_record_option)
        else:
            self._view.warn("Unknown command.")

    # step 2 : user deletes a calibration            

    def delete_a_calibration(self, true_false):
        if true_false is True:
            ident = self._record_ident
            calibrations = self._appdata['calibrations'] 
            cal_backup = calibrations.backup() 
            ok = calibrations.remove(ident)
            if ok:
                # delete the ranges records that use the calibration.
                # first get the idents of those ranges
                ranges = self._appdata['ranges']
                ran_backup = ranges.backup()
                ranges_remove_list = ranges.get_ranges_using_calibration(ident)
                for i in ranges_remove_list:
                    ok = ranges.remove(i)
                    if not ok:
                        break
                if ok:
                    # ranges were deleted so write the calibrations and ranges.
                    # backup, delete, restore if needed
                    ok, mess = calibrations.write()
                    if ok:
                        ok, mess = ranges.write()
                        if ok:
                            self._view.vm_show_calibration_deleted(ident)
            if ok:
                ranges_view = self._appdata['ranges_view']
                ranges_view.vm_remove_ranges(ranges_remove_list)
            else:
                calibrations.restore(cal_backup)
                ranges.restore(ran_backup)
                self._view.message_warn('Unable to delete %s.' % (self._record['description']))
        else:
            self._view.message_warn('Nothing deleted.')
                
    # step 2 : user edits a record
    # select calibrates one inch

    def w_calibrate(self):
        kwargs = {}
        if self._record_ident is not None:
            kwargs['back_handler'] = self.select_a_calibration_record_option
        # let the user select a target
        # self._record and self._record_ident are set
        self._view.select_calibration('Calibrate.',
                                      self._record['pixels'],
                                      self.w_handle_on_calibration_selected)

    def w_handle_on_calibration_selected(self, pixels):
        # the user has set the number of pixels in one inch.
        self._record['pixels'] = pixels
        # next is the description
        self.w_enter_description()
                                 
    # step 3 : describe the monitor and calibration
    
    def w_enter_description(self, **kwargs):
        kwargs['back_handler'] = self.w_calibrate 
        self._view.edit_line('Short description.',
                             'Enter a short description of the viewing device.',
                             self._record['description'],
                             self.w_handle_on_description_enter,
                             **kwargs)

    def w_handle_on_description_enter(self, description):
        # check length
        description = description.strip()
        if len(description) > 0:
            # make sure that the description is not already being used.
            calibrations = self._appdata['calibrations']
            ident = calibrations.get_ident_using_description(description)
            if ident is not None and ident != self._record_ident:
                help = 'You are already using the description "%s"'\
                       ' with another calibration.' % (description) 
                self.w_enter_description(help=help)
            else:
                self._record['description'] = description
                self._save_record()
        else:
            help = 'You did not enter any text.' 
            self.w_enter_description(help=help)

    # non public methods
    
    def _save_record(self):
        calibrations = self._appdata['calibrations']
        # save the record
        backup = calibrations.backup()
        if self._record_ident is None:
            ok, ident = calibrations.add(self._record_ident, self._record)
            if ok:
                ok, mess = calibrations.write()
            if ok:
                self._view.vm_show_calibration_added(ident, self._record['description'])
        else:
            ok = calibrations.set(self._record_ident, self._record)
            if ok:
                ok, mess = calibrations.write()
            if ok:
                self._view.vm_show_calibration_edited(self._record_ident, self._record['description'])
